import sys
import abstract_decoder
import re
from io import StringIO


class OokDecoder(abstract_decoder.AbstractDecoder):
    def __init__(self):
        super().__init__("Ook!")

    def decode(self, data, key=None ):
        # 先将 Ook! 代码转换为 Brainfuck 代码
        return self.ook_to_brainfuck(data)

    def clean_data(self, data):
        cleaned = data.strip().replace("\n", " ")
        # 补全样本数据
        if self._is_sample_valid(cleaned):
            cleaned = self._full_sample_data(cleaned)

        # 清洗ook里面的空格
        cleaned =  " ".join(cleaned.split())
        return cleaned

    def _is_sample_valid(self, data):
        # 检查是否只包含 Ook 组合
        pattern = r"^([.!?]\s*)*$"
        return bool(re.fullmatch(pattern, data))

    def _full_sample_data(self, data):
        # 补全样本数据
        data = data.replace(" ", "").replace("\n", "")
        sign_ooks = ['.', '!', '?']
        for sign in sign_ooks:
            data = data.replace(sign, f"Ook{sign} ")
        return data

    def is_valid(self, data, key = None):
        # 清洗数据
        cleaned = self.clean_data(data)
        cleaned = cleaned.replace(" ", "")
        # 检查是否只包含Ook组合
        pattern = r"^(Ook[.!?]\s*)*$"
        return bool(re.fullmatch(pattern, cleaned))

    def get_ook_map(self):
        return {
            "Ook. Ook?": ">",
            "Ook? Ook.": "<",
            "Ook. Ook.": "+",
            "Ook! Ook!": "-",
            "Ook! Ook.": ".",
            "Ook. Ook!": ",",
            "Ook! Ook?": "[",
            "Ook? Ook!": "]",
        }

    def split_ook(self, ook_code):
        # Ook! 到 Brainfuck 的映射
        ook_map = self.get_ook_map()

        # 分割 Ook! 代码为指令对
        ook_pairs = ook_code.split()
        return (len(ook_pairs) > 2, ook_pairs)

    def ook_to_brainfuck(self, ook_code):
        # 先清洗数据
        cleaned = self.clean_data(ook_code)
        # 验证 Ook! 代码是否有效
        vaild, ook_pairs = self.split_ook(cleaned)
        if not vaild:
            raise ValueError("Invalid Ook! code")

        ook_map = self.get_ook_map()
        brainfuck_code = []
        # 每两个 Ook 单词组成一个指令
        for i in range(0, len(ook_pairs), 2):
            pair = " ".join(ook_pairs[i : i + 2])
            if pair in ook_map:
                brainfuck_code.append(ook_map[pair])
            else:
                raise ValueError(f"Invalid Ook! pair: {pair}")

        return "".join(brainfuck_code)


if __name__ == "__main__":
    # 测试 Ook! 解码器
    ook_decoder = OokDecoder()
    # 测试解码
    files = ["test-data/ook.txt", "test-data/short_ook.txt"]
    for file in files:
        with open(file, "r") as f:
            data = f.read()
            print(f"Testing {file}...")
            print(ook_decoder.is_valid(data))
            print(ook_decoder.decode(data))
